package com.companyname.demo.cod.service;

import com.companyname.demo.cod.dao.EntryHeadMapper;
import com.companyname.demo.cod.dao.EntryListMapper;
import com.companyname.demo.cod.domain.AjaxResult;
import com.companyname.demo.cod.domain.EntryHead;
import com.companyname.demo.cod.domain.EntryList;
import com.companyname.demo.cod.util.JxlsUtil;
import com.companyname.demo.cod.util.MultiThreadDateUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.jxls.transformer.XLSTransformer;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j
public class EntryService {
    @Autowired
    private EntryHeadMapper entryHeadMapper;
    @Autowired
    private EntryListMapper entryListMapper;

    /**
     * 报关单列表分页查询
     */
    public AjaxResult selectEntryHeadPageList(EntryHead entryHead) {
        List<EntryHead> headList = entryHeadMapper.select(entryHead);
        return AjaxResult.success(headList);
    }

    /**
     * 根据seqNo获取商品列表
     */
    public AjaxResult selectGoodsListBySeqNo(String seqNo) {
        EntryList queryVO = new EntryList();
        queryVO.setSeqNo(seqNo);
        List<EntryList> result = entryListMapper.select(queryVO);
        return AjaxResult.success(result);
    }

    /**
     * excel导出，表头表体在不同sheet页
     * 采用模版：EntryInfo_HeadBodyEachSheet.xlsx
     * 该方法不能有return，否则报异常：Cannot call sendError() after the response has been committed
     */
    public void exportExcelHeadBodyEachSheet(String ids, String fileName, HttpServletResponse response) {
        Map<String, Object> resultMap = new HashMap<>();

        //1.组装表头数据
        List<String> idList = new ArrayList<>(Arrays.asList(ids.split(",")));
        Example headExample = new Example(EntryHead.class);
        Example.Criteria headCriteria = headExample.createCriteria();
        headCriteria.andIn("id", idList);
        List<EntryHead> headList = entryHeadMapper.selectByExample(headExample);
        resultMap.put("headlist", headList);
        //2.组装表体数据
        List<String> seqNoList = headList.stream().map(eachHead -> eachHead.getSeqNo()).collect(Collectors.toList());
        Example bodyExample = new Example(EntryList.class);
        Example.Criteria bodyCriteria = bodyExample.createCriteria();
        bodyCriteria.andIn("seqNo", seqNoList);
        List<EntryList> bodyList = entryListMapper.selectByExample(bodyExample);
        resultMap.put("bodylist", bodyList);
        //3.读取excel模板，使用JXLS工具将结果集组装为Workbook，再将Workbook写出到response
        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            if (StringUtils.isNotBlank(fileName)) {
                fileName += MultiThreadDateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx";
            } else {
                fileName = "ExcelExportNormal" + MultiThreadDateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx";
            }
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("application/vnd.ms-excel");

            inputStream = this.getClass().getResourceAsStream("/excelTemplate/EntryInfo_HeadBodyEachSheet.xlsx");
            XLSTransformer xlsTransformer = new XLSTransformer();
            Workbook workbook = xlsTransformer.transformXLS(inputStream, resultMap);
            outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
        } catch (InvalidFormatException e) {
            log.error("读取Excel模板组装Workbook时异常！", e);
        } catch (IOException e) {
            log.error("Workbook写出response时异常！", e);
        } finally {
            IOUtils.closeQuietly(outputStream);
            IOUtils.closeQuietly(inputStream);
        }
    }

    /**
     * excel导出，表头表体在同一个sheet页，多个sheet
     * 采用模版：EntryInfo_HeadBodySameMultiSheet.xlsx
     */
    public void exportExcelHeadBodySameMultiSheet(String ids, String fileName, HttpServletResponse response) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        List<String> newSheetNames = new ArrayList<>();//创建的新sheet的名字
        String beanName = "data";//这个要和excel模板里的参数是硬绑定
        //1.查询表头数据
        List<String> idList = new ArrayList<>(Arrays.asList(ids.split(",")));
        Example headExample = new Example(EntryHead.class);
        Example.Criteria headCriteria = headExample.createCriteria();
        headCriteria.andIn("id", idList);
        List<EntryHead> headList = entryHeadMapper.selectByExample(headExample);
        //2.查询表体数据，并将表头表体组装到map中
        headList.stream().forEach(eachHead -> {
            newSheetNames.add(eachHead.getSeqNo());//设定新sheet名字为seqNo
            EntryList query = new EntryList();
            query.setSeqNo(eachHead.getSeqNo());
            List<EntryList> bodyList = entryListMapper.select(query);
            Map<String, Object> map = new HashMap<>();
            map.put("head", eachHead);
            map.put("bodylist", bodyList);
            mapList.add(map);
        });

        //3.读取excel模板，使用JXLS工具将结果集组装为Workbook，再将Workbook写出到response
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            if (StringUtils.isNotBlank(fileName)) {
                fileName += MultiThreadDateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx";
            } else {
                fileName = "ExcelExportMultiSheet" + MultiThreadDateUtil.format(new Date(), "yyyyMMddHHmmss") + ".xlsx";
            }
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("application/vnd.ms-excel");

            inputStream = this.getClass().getResourceAsStream("/excelTemplate/EntryInfo_HeadBodySameMultiSheet.xlsx");
            XLSTransformer xlsTransformer = new XLSTransformer();
            Workbook workbook = xlsTransformer.transformMultipleSheetsList(inputStream, mapList, newSheetNames, beanName, null, 0);
            outputStream = response.getOutputStream();
            workbook.write(outputStream);
        } catch (InvalidFormatException e) {
            log.error("读取Excel模板组装Workbook时异常！", e);
        } catch (IOException e) {
            log.error("Workbook写出response时异常！", e);
        } finally {
            IOUtils.closeQuietly(outputStream);
            IOUtils.closeQuietly(inputStream);
        }
    }

    /**
     * excel导出，表头表体在同一个sheet页，多个excel压缩zip导出
     * 采用模版：EntryInfo_HeadBodySameSheet.xlsx
     */
    public void exportExcelSameSheetZipBatch(String ids, String fileName, HttpServletResponse response) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        //1.查询表头数据
        List<String> idList = new ArrayList<>(Arrays.asList(ids.split(",")));
        Example headExample = new Example(EntryHead.class);
        Example.Criteria headCriteria = headExample.createCriteria();
        headCriteria.andIn("id", idList);
        List<EntryHead> headList = entryHeadMapper.selectByExample(headExample);
        //2.查询表体数据，并将表头表体组装到map中
        headList.stream().forEach(eachHead -> {
            EntryList query = new EntryList();
            query.setSeqNo(eachHead.getSeqNo());
            List<EntryList> bodyList = entryListMapper.select(query);
            Map<String, Object> map = new HashMap<>();
            map.put("head", eachHead);
            map.put("bodylist", bodyList);
            mapList.add(map);
        });
        //3.遍历mapList，读取excel模板，写入zip输出流中
        InputStream inputStream = null;
        OutputStream outputStream = null;
        ZipOutputStream zipOutputStream = null;
        try {
            if (StringUtils.isBlank(fileName)) {
                fileName = "ExcelExportBatch";
            }
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + MultiThreadDateUtil.format(new Date(), "yyyyMMddHHmmss") + ".zip");
            response.setContentType("application/vnd.ms-excel");

            outputStream = response.getOutputStream();
            zipOutputStream = new ZipOutputStream(outputStream);
            //遍历每个map，生成一个excel文件写入到zipOutputStream中
            for (Map<String, Object> eachMap : mapList) {
                try {
                    inputStream = this.getClass().getResourceAsStream("/excelTemplate/EntryInfo_HeadBodySameSheet.xlsx");
                    XLSTransformer xlsTransformer = new XLSTransformer();
                    Workbook workbook = xlsTransformer.transformXLS(inputStream, eachMap);
                    JxlsUtil.OwnerOutputStream ownerOutputStream = new JxlsUtil.OwnerOutputStream(zipOutputStream);
                    //fileName每个输出流要不一样，否则报异常：duplicate entry
                    String entryFileName = fileName + new StringBuilder("_").append(RandomUtils.nextInt()).append(".xlsx");
                    ownerOutputStream.putNextEntry(entryFileName);
                    workbook.write(ownerOutputStream);
                    ownerOutputStream.flush();
                } catch (InvalidFormatException | IOException e) {
                    log.error("遍历maplist写出到ownerOutputStream时异常！", e);
                }
            }
            zipOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(zipOutputStream);
            IOUtils.closeQuietly(outputStream);
            IOUtils.closeQuietly(inputStream);
        }


    }
}

